using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Text;

/// <summary>
/// 表示ZIP文件中的一个资源文件
/// </summary>
public class ZipAssetFile {
  public ZipAssets Owner { get; }
  public string Path { get; }          // 原始路径
  public string LowerCasePath { get; } // 小写路径(用于不区分大小写查询)

  public ZipAssetFile(ZipAssets owner, string path) {
    Owner = owner;
    Path = path ?? throw new ArgumentNullException(nameof(path));
    LowerCasePath = path.ToLowerInvariant();
  }

  internal byte[] GetBytes() {
    return Owner.GetBytes(Path);
  }
}

public class ZipAssets : IDisposable {
  public string FilePath { get; }
  private readonly Dictionary<string, ZipAssetFile> _fileDictionary =
      new Dictionary<string, ZipAssetFile>(StringComparer.OrdinalIgnoreCase);
  private ZipArchive _archive;
  private FileStream _fileStream;
  private bool _disposed;

  /// <summary>
  /// 初始化ZipAssets
  /// </summary>
  /// <param name="zipPath">ZIP文件路径</param>
  public ZipAssets(string zipPath) {
    FilePath = zipPath ?? throw new ArgumentNullException(nameof(zipPath));

    if (!File.Exists(zipPath))
      throw new FileNotFoundException("ZIP文件不存在", zipPath);

    // 保持文件流和ZipArchive常驻内存
    _fileStream = File.OpenRead(zipPath);
    _archive = new ZipArchive(_fileStream, ZipArchiveMode.Read, false);

    InitializeFileDictionary();
  }

  /// <summary>
  /// 初始化文件字典
  /// </summary>
  private void InitializeFileDictionary() {
    foreach (var entry in _archive.Entries) {
      if (string.IsNullOrEmpty(entry.Name))
        continue; // 跳过目录条目

      // 添加到字典
      var assetFile = new ZipAssetFile(this, entry.FullName);
      _fileDictionary[assetFile.LowerCasePath] = assetFile;
    }
  }

  /// <summary>
  /// 获取文件的字节数据
  /// </summary>
  public byte[] GetBytes(string path) {
    if (_disposed)
      throw new ObjectDisposedException(nameof(ZipAssets));

    if (string.IsNullOrWhiteSpace(path))
      throw new ArgumentNullException(nameof(path));

    string lowerPath = path.ToLowerInvariant();
    if (!_fileDictionary.TryGetValue(lowerPath, out var fileInfo))
      throw new FileNotFoundException($"文件 '{path}' 不在ZIP包中");

    return GetBytesInternal(path);
  }

  private byte[] GetBytesInternal(string path) {
    var entry = _archive.GetEntry(path);
    if (entry == null)
      throw new FileNotFoundException($"ZIP中找不到文件: {path}");

    using (var entryStream = entry.Open())
    using (var memoryStream = new MemoryStream()) {
      entryStream.CopyTo(memoryStream);
      return memoryStream.ToArray();
    }
  }

  internal ZipAssetFile GetItem(string relativePath) {
    string lowerPath = relativePath.ToLowerInvariant().Replace("\\", "/");
    _fileDictionary.TryGetValue(lowerPath, out var fileInfo);

    if (fileInfo == null) {
      Debuger.LogError($"Unable find {lowerPath} in {FilePath}");
    }
    return fileInfo;
  }

  /// <summary>
  /// 获取文件的UTF-8文本内容
  /// </summary>
  public string GetString(string path) {
    byte[] bytes = GetBytes(path);
    return Encoding.UTF8.GetString(bytes);
  }

  /// <summary>
  /// 获取ZIP包中所有文件的路径列表
  /// </summary>
  public IEnumerable<string> GetAllFilePaths() {
    foreach (var file in _fileDictionary.Values) {
      yield return file.Path;
    }
  }

  /// <summary>
  /// 检查文件是否存在
  /// </summary>
  public bool ContainsFile(string path) {
    if (string.IsNullOrWhiteSpace(path))
      return false;

    return _fileDictionary.ContainsKey(path.ToLowerInvariant());
  }

  /// <summary>
  /// 释放资源
  /// </summary>
  public void Dispose() {
    if (_disposed) return;

    _fileDictionary.Clear();
    _archive?.Dispose();
    _fileStream?.Dispose();

    _disposed = true;
  }
}